﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using SpeechLib;
using System.Speech;
using System.Speech.Recognition;
using System.IO;
using System.Diagnostics;
using System.Reflection;

namespace Pearl
{
    //[ComVisibleAttribute(true)]
    public partial class FrmIndex : Form
    {
        SpeechRecognitionEngine speechRecognitionEngine;
        Grammar grammer;
        Dictionary<string, string> wordList;
        List<string> applicationList = new List<string>();
        Choices choicesApplication = new Choices();
        GrammarBuilder grammerBuilder = new GrammarBuilder();
        public FrmIndex()
        {
            InitializeComponent();
        }

        private bool isShow = false;

        [DllImport("user32.dll")]
        public static extern bool RegisterHotKey(IntPtr hwnd, int id, uint fsModifiers, Keys vk);
        [DllImport("user32.dll")]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

        internal AnchorStyles StopAanhor = AnchorStyles.None;
        private const int WS_SHOWNORMAL = 1;

        #region 私有方法
        //判断应该隐藏哪一遍
        private void mStopAnhor()
        {
            if (this.Top <= 0 && this.Left <= 0)
                StopAanhor = AnchorStyles.None;
            else if (this.Top <= 0)
                StopAanhor = AnchorStyles.Top;
            else if (this.Left <= 0)
                StopAanhor = AnchorStyles.Left;
            else if (this.Left >= Screen.PrimaryScreen.Bounds.Width - this.Width)
                StopAanhor = AnchorStyles.Right;
            else if (this.Top >= Screen.PrimaryScreen.Bounds.Height - this.Height)
                StopAanhor = AnchorStyles.Bottom;
            else
                StopAanhor = AnchorStyles.None;
        }
        //显示窗体
        private void showForm()
        {
            switch (this.StopAanhor)
            {
                case AnchorStyles.Top:
                    this.Location = new Point(this.Location.X, 0);
                    break;
                case AnchorStyles.Left:
                    this.Location = new Point(0, this.Location.Y);
                    break;
                case AnchorStyles.Right:
                    this.Location = new Point(Screen.PrimaryScreen.Bounds.Width - this.Width, this.Location.Y);
                    break;
                case AnchorStyles.Bottom:
                    this.Location = new Point(this.Location.X, Screen.PrimaryScreen.Bounds.Height - this.Height);
                    break;
            }
        }
        //隐藏窗体
        private void hideForm()
        {
            switch (this.StopAanhor)
            {
                case AnchorStyles.Top:
                    this.Location = new Point(this.Location.X, (this.Height - 4) * (-1));
                    break;
                case AnchorStyles.Left:
                    this.Location = new Point((-1) * (this.Width - 4), this.Location.Y);
                    break;
                case AnchorStyles.Right:
                    this.Location = new Point(Screen.PrimaryScreen.Bounds.Width - 4, this.Location.Y);
                    break;
                case AnchorStyles.Bottom:
                    this.Location = new Point(this.Location.X, (Screen.PrimaryScreen.Bounds.Height - 4));
                    break;
            }
        }
        private void SetProgame()
        {
            int oldCount = applicationList.Count;
            Process[] ps = Process.GetProcesses();
            foreach (Process p in ps)
            {
                string title = p.MainWindowTitle;
                if (p.MainWindowHandle != null && !string.IsNullOrEmpty(p.MainWindowTitle))
                {
                    string application = applicationList.FirstOrDefault(z => z == title);
                    if (string.IsNullOrEmpty(application))
                    {
                        applicationList.Add(title);
                    }
                }
            }
            applicationList.Add("桌面");
            if (oldCount != applicationList.Count)
            {
                foreach (string application in applicationList)
                {
                    choicesApplication.Add(application);
                    Console.WriteLine(application);
                }
                grammerBuilder.Append(choicesApplication);
            }
        }
        #endregion

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (this.Bounds.Contains(Cursor.Position))
            {
                showForm();
                isShow = false;
            }
            else
            {
                if (!isShow)
                {
                    hideForm();
                }
            }
        }

        protected override void WndProc(ref Message m)
        {
            const int WM_HOTKEY = 0x0312;
            const int WM_SYSCOMMAND = 0x0112;
            const int SC_CLOSE = 0xF060;
            //按快捷键
            switch (m.Msg)
            {
                case WM_HOTKEY:
                    switch (m.WParam.ToInt32())
                    {
                        case 101:    //F1 显示窗体
                            showForm();
                            isShow = true;
                            break;
                    }
                    break;
                case WM_SYSCOMMAND:
                    //屏蔽Alt+F4
                    if ((m.WParam.ToInt32() & 0xFFF0) == SC_CLOSE
                        && m.LParam.ToInt32() == 0)
                    {
                        return;
                    }
                    break;
            }
            base.WndProc(ref m);
        }

        public void ShowMessageBox(string message)
        {
            MessageBox.Show(message);
        }
        private void FrmIndex_Load(object sender, EventArgs e)
        {
            this.TopMost = true;
            this.timer1.Start();

            lblTitle.Text = string.Format("你能说{0}！", GetLanguageStr());

            speechRecognitionEngine = new SpeechRecognitionEngine();

            //使用系统默认麦克风
            speechRecognitionEngine.SetInputToDefaultAudioDevice();
            //自己的语法

            string[] lines = File.ReadAllLines(Environment.CurrentDirectory + "\\grammar.txt");

            Choices choicesCommand = new Choices();
            Choices choicesProgame = new Choices();
            Choices choicesArguments = new Choices();
            wordList = new Dictionary<string, string>();
            foreach (string line in lines)
            {
                if (line == String.Empty || line == new string('-', 10))
                {
                    continue;
                }

                var parts = line.Split(new char[] { '|' });

                // add commandItem to the list for later lookup or execution
                //wordList.Add(new Model.Word() { Text = parts[0], AttachedText = parts[1], Type = parts[2] });
                wordList.Add(parts[0], parts[1]);

                // add the text to the known choices of speechengine
                if (parts[2] == "1")
                {
                    choicesCommand.Add(parts[0]);
                }
                if (parts[2] == "2")
                {
                    choicesProgame.Add(parts[0]);
                }
                if (parts[2] == "3")
                {
                    choicesArguments.Add(parts[0]);
                }
            }

            //SemanticResultKey choiceResultKey = new SemanticResultKey("Command", new string[] { "Open", "打开", "开启" });
            //grammerBuilder.Append(choiceResultKey);
            //choiceResultKey = new SemanticResultKey("Result", new string[] { "QQ", "IE", "我的电脑" });
            //grammerBuilder.Append(choiceResultKey);
            //grammerBuilder.AppendRuleReference(Environment.CurrentDirectory + "\\grammar.xml");
            //grammerBuilder.Append(new Choices(new string[] { "Open", "打开", "开启" }));
            //grammerBuilder.Append(new Choices(new string[] { "QQ", "IE", "我的电脑" }));
            grammerBuilder.Append(choicesCommand);
            grammerBuilder.Append(choicesProgame);
            grammerBuilder.Append(choicesArguments);
            SetProgame();

            grammer = new Grammar(grammerBuilder);
            //识别之后的事件
            grammer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(G_SpeechRecognized);
            //删除所有语法
            speechRecognitionEngine.UnloadAllGrammars();
            //加载语法
            speechRecognitionEngine.LoadGrammar(grammer);
            //开始听
            speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);
        }

        private void FrmIndex_LocationChanged(object sender, EventArgs e)
        {
            this.mStopAnhor();
        }

        private void FrmIndex_Activated(object sender, EventArgs e)
        {
            RegisterHotKey(Handle, 101, 0, Keys.F1); //注册F1热键,显示窗体
        }

        private void FrmIndex_Click(object sender, EventArgs e)
        {
            SpeechVoiceSpeakFlags spFlags = SpeechVoiceSpeakFlags.SVSFDefault;//异步说话SVSFlagsAsync
            SpVoice voice = new SpVoice();
            voice.Speak("你好，有什么可以帮助的？", spFlags);
        }
        void G_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            this.lblResult.Invoke(new MethodInvoker(delegate()
            {
                this.lblResult.Text = e.Result.Text;
            }));
            string command = null, progame = null, oldProgame = null, arguments = null, oldArguments = null;
            for (int i = 0; i < e.Result.Words.Count; i++)
            {
                if (i == 0)
                {
                    if (wordList.ContainsKey(e.Result.Words[0].Text))
                    {
                        command = wordList[e.Result.Words[0].Text];
                    }
                }
                if (i == 1)
                {
                    oldProgame = e.Result.Words[1].Text;
                    if (wordList.ContainsKey(oldProgame))
                    {
                        progame = wordList[oldProgame];
                    }
                }
                if (i == 2)
                {
                    oldArguments = e.Result.Words[2].Text;
                    if (wordList.ContainsKey(oldArguments))
                    {
                        arguments = wordList[oldArguments];
                    }
                }
            }

            switch (command)
            {
                case "Open":
                    try
                    {
                        Process.Start(progame, arguments);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
                case "Back":
                    if (oldArguments == "桌面")
                    {
                        Type oleType = Type.GetTypeFromProgID("Shell.Application");
                        object oleObject = System.Activator.CreateInstance(oleType);
                        oleType.InvokeMember("ToggleDesktop", BindingFlags.InvokeMethod, null, oleObject, null);
                    }
                    else
                    {
                        IntPtr parenthWnd = new IntPtr(0);
                        parenthWnd = FindWindow(null, oldArguments);
                        //SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                        //SetWindowPos(HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                        ShowWindowAsync(parenthWnd, WS_SHOWNORMAL);
                        SetForegroundWindow(parenthWnd);
                    }
                    break;
            }
        }

        string GetLanguageStr()
        {
            string strLanguages = "英文";
            foreach (RecognizerInfo config in SpeechRecognitionEngine.InstalledRecognizers())
            {
                if (config.Culture.ToString() == "zh-CN")
                {
                    strLanguages += "、中文";
                    //break;
                }
            }
            return strLanguages;
        }

        private void FrmIndex_FormClosed(object sender, FormClosedEventArgs e)
        {
            speechRecognitionEngine.RecognizeAsyncStop();
            speechRecognitionEngine.UnloadGrammar(grammer);
            speechRecognitionEngine.Dispose();
            Application.ExitThread();
            Application.Exit();
        }
    }
}
